﻿#include "pch.h"
#include "common.h"
#include "contact.h"
#include <atlstr.h>

using namespace std;

typedef tuple <
	//wxid1
	wstring,
	//wxName
	wstring,
	//v1
	wstring,
	//nickName
	wstring
> USER_INFO;
//定义7000个用户列表
list<USER_INFO> userInfoList(1);

//用于暂存用户数据
DWORD hookAddress;
DWORD hookAddressCall;
DWORD jumBackAddress;
BYTE bBackCode[5] = { 0 };

//用于保存寄存器状态
DWORD cEax = 0;
DWORD cEcx = 0;
DWORD cEdx = 0;
DWORD cEbx = 0;
DWORD cEsp = 0;
DWORD cEbp = 0;
DWORD cEsi = 0;
DWORD cEdi = 0;

//取消hook联系人列表
void UnHookContactList(DWORD BaseAddr) {
	hookAddress = BaseAddr + OFFSET_CONTACT_LIST;
	// 因为要往代码段写入数据，又因为代码段是不可写的，所以需要修改属性
	DWORD OldProtext = 0;
	VirtualProtect((LPVOID)hookAddress, 5, PAGE_EXECUTE_READWRITE, &OldProtext);
	memcpy((void*)hookAddress, bBackCode, 5);
	// 执行完了操作之后需要进行还原
	VirtualProtect((LPVOID*)hookAddress, 5, OldProtext, &OldProtext);
}

//hook联系人列表
void HookContactList(DWORD BaseAddr)
{
	//需要hook的地址
	hookAddress = BaseAddr + OFFSET_CONTACT_LIST;
	hookAddressCall = BaseAddr + OFFSET_CONTACT_INFO;

	//跳回的地址
	jumBackAddress = hookAddress + 5;

	//组装跳转数据
	BYTE jmpCode[5] = { 0 };
	jmpCode[0] = 0xE9;

	//计算偏移
	*(DWORD*)&jmpCode[1] = (DWORD)NakedUserINfo - hookAddress - 5;

	// 保存以前的属性用于还原
	DWORD OldProtext = 0;

	// 因为要往代码段写入数据，又因为代码段是不可写的，所以需要修改属性
	VirtualProtect((LPVOID)hookAddress, 5, PAGE_EXECUTE_READWRITE, &OldProtext);

	//保存原有的指令
	memcpy(bBackCode, (void*)hookAddress, 5);

	//写入自己的代码
	memcpy((void*)hookAddress, jmpCode, 5);

	// 执行完了操作之后需要进行还原
	VirtualProtect((LPVOID)hookAddress, 5, OldProtext, &OldProtext);
}

//发送用户信息
void SendUserListInfo()
{
	//个人微信号、群号
	wstring wxid1 = GetMsgByAddress(cEax + 0x08);
	wstring wxName = GetMsgByAddress(cEax + 0x1c);
	//个人微信昵称、群昵称
	wstring v1 = GetMsgByAddress(cEax + 0x30);
	wstring nickName = GetMsgByAddress(cEax + 0x64);
	USER_INFO userInfo(wxid1, wxName, v1, nickName);

	for (auto& userInfoOld : userInfoList)
	{
		wstring wxid = get<0>(userInfoOld);
		if (wxid == wxid1)
		{
			return;
		}
	}
	userInfoList.push_front(userInfo);

	UserInfo* user = new UserInfo;
	LPVOID pUserWxid = *((LPVOID*)(cEax + 0x08));
	LPVOID pUserNumber = *((LPVOID*)(cEax + 0x1c));
	LPVOID pUserNick = *((LPVOID*)(cEax + 0x64));
	LPVOID pUserReMark = *((LPVOID*)(cEax + 0x50));

	swprintf_s(user->UserId, L"%s", (wchar_t*)pUserWxid);
	swprintf_s(user->UserNumber, L"%s", (wchar_t*)pUserNumber);
	swprintf_s(user->UserNickName, L"%s", (wchar_t*)pUserNick);
	swprintf_s(user->UserRemark, L"%s", (wchar_t*)pUserReMark);

	//发送到控制端
	//HWND hWnd = FindWindow(NULL, TEXT("微信助手"));
	//if (hWnd == NULL)
	//{
	//	//创建线程 发送消息 防止漏掉联系人
	//	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReSendUser, user, 0, NULL);
	//}

	COPYDATASTRUCT userinfo;
	userinfo.dwData = MT_CONTACT_LIST;//保存一个数值, 可以用来作标志等
	userinfo.cbData = sizeof(UserInfo);// strlen(szSendBuf);//待发送的数据的长
	userinfo.lpData = user;// szSendBuf;//待发送的数据的起始地址(可以为NULL)

	MessageSender(userinfo);
}

//获取用户信息裸函数
__declspec(naked) void NakedUserINfo() {
	//执行汇编码
	_asm {

		//获取用户信息call
		call hookAddressCall

		//保存寄存器状态
		mov cEax, eax
		mov cEcx, ecx
		mov cEdx, edx
		mov cEbx, ebx
		mov cEsp, esp
		mov cEbp, ebp
		mov cEsi, esi
		mov cEdi, edi

	}

	SendUserListInfo();

	//恢复现场
	__asm
	{

		//恢复现场
		mov eax, cEax
		mov ecx, cEcx
		mov edx, cEdx
		mov ebx, cEbx
		mov esp, cEsp
		mov ebp, cEbp
		mov esi, cEsi
		mov edi, cEdi

		//跳回被HOOK指令的下一条指令
		jmp jumBackAddress
	}
}
